"""
proxy for an html canvas
"""

class Canvas:
    def __init__(self):
        self.minx = self.miny = None
        self.maxx = self.maxy = None
        self.program = []
    def xAdjust(self, x):
        if self.maxx is not None:
            self.maxx = max(self.maxx, x)
        else:
            self.maxx = x
        if self.minx is not None:
            self.minx = min(self.minx, x)
        else:
            self.minx = x
        return XAdjust(self, x)
    def yAdjust(self, y):
        if self.maxy is not None:
            self.maxy = max(self.maxy, y)
        else:
            self.maxy = y
        if self.miny is not None:
            self.miny = min(self.miny, y)
        else:
            self.miny = y
        return YAdjust(self, y)
    def setColor(self, r,g,b):
        cmd = "contexto.fillStyle = '%s';" % hexcolor(r,g,b)
        self.program.append(cmd)
        cmd = "contexto.strokeStyle = '%s';" % hexcolor(r,g,b)
        self.program.append(cmd)
    def addLines(self, points):
        assert len(points)>1
        cmd = "contexto.beginPath();"
        self.program.append(cmd)
        (x,y) = points[0]
        cmd = Adjusted("contexto.moveTo(%s, %s);", (self.xAdjust(x),self.yAdjust(y)))
        self.program.append(cmd)
        for (x,y) in points[1:]:
            cmd = Adjusted("contexto.lineTo(%s, %s);", (self.xAdjust(x),self.yAdjust(y)))
            self.program.append(cmd)            
        cmd = "contexto.stroke();"
        self.program.append(cmd)
    def addRect(self, x,y,w,h,callbackName=None):
        self.xAdjust(x+w)
        self.yAdjust(y+h)
        self.yAdjust(y)
        cmd = Adjusted("contexto.fillRect(%s,%s,%s,%s);", (self.xAdjust(x),self.yAdjust(y+h),w,h))
        self.program.append(cmd);
        if callbackName is not None:
            cmd = Adjusted("boxes.push([%s,%s,%s,%s,%s]);", (self.xAdjust(x),self.yAdjust(y+h),self.xAdjust(x+w),self.yAdjust(y),
                                                             repr(str(callbackName))))
            self.program.append(cmd)
    def setFont(self, fontname, scale, dummyForCompatibility):
        pts = int(9*scale)
        fontdescription = "%spt %s" % (pts, fontname)
        cmd = "contexto.font = '%s';" % fontdescription
        self.program.append(cmd);
    def addText(self, x,y,txt,maxwidth=None):
        if maxwidth==None:
            maxwidth = 7*len(txt) # XXXX TEMPORARY HACK
        cmd = Adjusted("contexto.fillText(%s, %s, %s, %s);", (repr(str(txt)), self.xAdjust(x), self.yAdjust(y), maxwidth))
        self.program.append(cmd);
    def addCircle(self, x,y,radius):
        # XXXX temporarily emulate using a rectangle...
        #self.addRect(x-radius, y-radius, radius*2, radius*2)
        cmd = "contexto.beginPath();"
        self.program.append(cmd)
        cmd = Adjusted("contexto.arc(%s, %s, %s, 0, 6.29, true);", (self.xAdjust(x),self.yAdjust(y),radius))
        self.program.append(cmd)
        cmd = "contexto.closePath();"
        self.program.append(cmd)
        cmd = "contexto.stroke();"
        self.program.append(cmd)
    def programText(self, canvasId, minWidth, minHeight, boxClickCallBack=None, eventListenerVariable=None):
        program = [str(x) for x in self.program]
        programBody = "    "+"\n    ".join(program)
        D = {}
        D["programBody"] = programBody
        D["canvasId"] = canvasId
        if self.maxx==self.minx:
            D["canvasWidth"] = minWidth
        else:
            D["canvasWidth"] = max(self.maxx-self.minx, minWidth)
        if self.maxy==self.miny:
            D["canvasHeight"] = minHeight
        else:
            D["canvasHeight"] = max(self.maxy-self.miny, minHeight)
        if boxClickCallBack:
            assert eventListenerVariable, "must store event listener somewhere"
            D["eventListener"] = '%s = AddBoxEventListener(canvaso, boxes, %s, "click", %s);' % (
                eventListenerVariable,
                boxClickCallBack,
                eventListenerVariable)
        else:
            D["eventListener"] = '//no event listener'
        return CANVAS_PROGRAM_TEMPLATE % D
    def dumpTestHtml(self, outfile):
        program = self.programText("testCanvas", 100, 100, "canvasClickCallback")
        D = {}
        D["program"] = program
        D["outfile"] = outfile
        txt = TEST_HTML_TEMPLATE % D
        print "writing test output file", outfile
        open(outfile, "w").write(txt)
        return txt

TEST_HTML_TEMPLATE = """
<HTML>
<HEAD>

<script type="text/javascript" src="boxed.js"></script>

<script type="text/javascript">

function canvasClickCallback(data, x, y, canvas, ev) {
         ////al("callback "+data+", "+x+", "+y);
         var promptDiv = document.getElementById("promptDiv");
         promptDiv.innerHTML = "callback "+data+", "+x+", "+y;
         promptDiv.style.visibility = "visible";
}


function setUpCanvas() {
%(program)s

}

</script>
</HEAD>
<BODY onload="setUpCanvas()">
<h3> canvas test page %(outfile)s </h3>

<table border><tr><td>
<div id="container">
<canvas id="testCanvas" width="100" height="100">
canvas tag not supported?
</canvas>
</div>
</td></tr></table>

<div id="promptDiv" class="jswhiff_suggestion" style="width:400px; visibility:hidden">
mouse event prompt will be displayed here
</div>


<h3>end of test page %(outfile)s</h3>
</BODY>
</HTML>
"""

class Adjusted:
    def __init__(self, pattern, arguments):
        self.pattern = pattern
        self.arguments = arguments
    def __str__(self):
        strargs = tuple( [str(x) for x in self.arguments] )
        result = self.pattern % strargs
        return result

class XAdjust:
    def __init__(self, canvas, x):
        self.x = x
        self.canvas = canvas
    def __str__(self):
        xadj = self.x - self.canvas.minx
        return str(xadj)

class YAdjust:
    def __init__(self, canvas, y):
        self.y = y
        self.canvas = canvas
    def __str__(self):
        #yadj = self.y - self.canvas.miny
        yadj = self.canvas.maxy-self.y
        return str(yadj)

CANVAS_PROGRAM_TEMPLATE = """
    var boxes = [];
    var canvaso = document.getElementById('%(canvasId)s');
    canvaso.width = %(canvasWidth)s;
    canvaso.height = %(canvasHeight)s;
    var contexto = canvaso.getContext('2d');
    %(programBody)s
    //for (var i=0; i<boxes.length; i++) {
    ////al("box["+i+"]="+boxes[i]);
    //}
    %(eventListener)s
"""

def hexcolor(r,g,b):
    hexstrings = [ '%02X'%x for x in (r,g,b) ]
    hexstring = "".join(hexstrings)
    return "#"+hexstring

